package ru.pb.game.objects.model.inventory;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import ru.pb.game.dao.ItemsDAO;
import ru.pb.game.data.xml.holders.ItemHolder;
import ru.pb.game.objects.model.items.Item;
import ru.pb.game.objects.model.items.enums.ItemLocation;
import ru.pb.game.objects.storage.IStoreableObject;
import ru.pb.game.objects.storage.ObjectsStorage;
import ru.pb.global.dao.DAOManager;

/**
 * @author Felixx
 * @param <OWNER>
 */
public abstract class ItemContainer<OWNER extends IStoreableObject>
{
	private static final ItemsDAO _dao = DAOManager.getDAOImpl(ItemsDAO.class);
	protected long _storedId;
	protected final Queue<Item> _items = new ConcurrentLinkedQueue<Item>();

	protected ItemContainer(OWNER owner)
	{
		setOwner(owner);
	}

	// ======================================================================================================
	// addItem sector
	// ======================================================================================================
	public Item addItem(int itemId, int count)
	{
		Item item = ItemHolder.getInstance().createItem(itemId);
		item.setCount(count);
		return addItem(item);
	}

	public Item addItem(Item newItem)
	{
		return addItem(newItem, true);
	}

	protected Item addItem(Item newItem, boolean dbUpdate)
	{
		OWNER owner = getOwner();
		if(owner == null)
			return null;

		Item oldItem;
		Item result;

		if( !newItem.isStackable() || (oldItem = getItemByItemId(newItem.getItemId())) == null)
		{
			// ставим овенера и тип контейнера, ток если овнеры разные
			if(newItem.getOwnerObjectId() != owner.getObjectId())
			{
				newItem.setOwnerObjectId(owner.getObjectId());
				newItem.setLocation(getBaseLocation());
			}

			// если нужно обновляем базу даных
			if(dbUpdate)
				newItem.updateDatabase(null, true);

			getItemsQueue().add(newItem);

			result = newItem;
		}
		else
		{
			oldItem.setCount(oldItem.getCount() + newItem.getCount());
			oldItem.updateDatabase(null, true);

			// мы ищо не в инвентаре,не нужно посылать пакеты
			newItem.fullDestroy();

			// если нужно обновляем базу даных
			if(dbUpdate)
			{
				oldItem.updateDatabase(null, true);
				newItem.updateDatabase(null, true);
			}
			result = oldItem;
		}

		return result;
	}

	// ======================================================================================================
	// destroyItem sector
	// ======================================================================================================
	public Item destroyItemByObjectId(int objectId, int count)
	{
		Item item = getItemByObjectId(objectId);
		return destroyItem(item, item == null ? 0 : count);
	}

	public Item destroyItemByItemId(int itemId, int count, String toLog)
	{
		Item item = getItemByItemId(itemId);
		return destroyItem(item, count);
	}

	public Item destroyItem(Item item)
	{
		return destroyItem(item, item == null ? 0 : item.getCount());
	}

	public Item destroyItem(Item item, int count)
	{
		OWNER owner = getOwner();
		if(owner == null)
			return null;

		if(item == null)
			return null;

		if( !getItemsQueue().contains(item))
			return null;

		if(item.getCount() < count)
			count = item.getCount();

		if(item.getCount() == count)
		{
			item.fullDestroy();

			getItemsQueue().remove(item);
		}
		else
		{
			item.setCount(item.getCount() - count);
			item.updateDatabase(null, true);
		}

		return item;
	}

	// ======================================================================================================
	// restoreMe sector
	// ======================================================================================================
	public void restoreMe(Connection con)
	{
		_dao.select(con, this);
	}

	public void databaseRestore(Item item)
	{
		if(item == null)
			return;

		Item newItem = addItem(item, false);
		if(newItem == null)
			return;

		if(item != newItem)
		{
			item.updateDatabase();
			newItem.updateDatabase();
		}
	}

	public void deleteMe()
	{
		updateMe(null);
		_items.clear();
	}

	public void updateMe(Connection con)
	{
		for(Item item : getItemsQueue())
		{
			if(item != null)
			{
				item.updateDatabase(con, true);
				item.deleteMe(false);
			}
		}
	}

	// ======================================================================================================
	// transfer sector
	// ======================================================================================================
	public Item transfer(Item item, ItemContainer<?> toContainer)
	{
		return transfer(item, item == null ? 0 : item.getCount(), toContainer);
	}

	public Item transfer(int itemId, ItemContainer<?> toContainer)
	{
		Item item = getItemByItemId(itemId);
		return transfer(item, item == null ? 0 : item.getCount(), toContainer);
	}

	public Item transfer(Item item, int count, ItemContainer<?> toContainer)
	{
		OWNER owner = getOwner();
		if(owner == null)
			return null;

		if(item == null || count <= 0)
			return null;

		if(item.getOwnerObjectId() != owner.getObjectId())
			return null;

		item.setLocation(toContainer.getBaseLocation());

		// если количество которое взять равно количеству которое нужно
		if(item.getCount() == count)
		{
			getItemsQueue().remove(item);

			toContainer.addItem(item);
			return item;
		}
		else
		{
			// создаем новый итем
			Item newItem = item.clone();
			newItem.setCount(count);
			// добавляем итем
			toContainer.addItem(newItem);

			// уменьшаем количество
			item.setCount(item.getCount() - count);
			item.updateDatabase(null, true);

			return newItem;
		}
	}

	// ======================================================================================================
	// drop sector
	// предподчительно кругом использовать transfer
	// ======================================================================================================
	public Item removeItemByObjectId(int itemObjectId, int count)
	{
		Item item = getItemByObjectId(itemObjectId);
		if(item == null)
			return null;

		return removeItem(item, count);
	}

	public Item removeItem(Item item, int count)
	{
		OWNER owner = getOwner();
		if(owner == null)
			return null;

		if(item == null || count <= 0)
			return null;

		if(item.getOwnerObjectId() != getOwnerId())
			return null;

		// если количество которое взять равно количеству которое нужно
		if(item.getCount() == count)
		{
			getItemsQueue().remove(item);

			item.removeFromInventory();

			return item;
		}
		else
		{
			// уменьшаем количество
			item.setCount(item.getCount() - count);

			// создаем новый итем
			Item newItem = ItemHolder.getInstance().createItem(item.getItemId());
			newItem.setCount(count);

			item.updateDatabase(null, true);

			return newItem;
		}
	}

	// ======================================================================================================
	// getters sector
	// ======================================================================================================
	public long getCountOf(int itemId)
	{
		Item item = getItemByItemId(itemId);

		return item == null ? 0 : item.getCount();
	}

	public Item getItemByItemId(int itemId)
	{
		for(Item item : getItemsQueue())
		{
			if(item.getItemId() == itemId)
				return item;
		}

		return null;
	}

	public List<Item> getAllItemsById(final int itemId)
	{
		final List<Item> ar = new ArrayList<Item>();
		for(final Item i : getItemsQueue())
		{
			if(i.getItemId() == itemId)
				ar.add(i);
		}
		return ar;
	}

	public Item getItemByObjectId(int obj_id)
	{
		for(Item item : getItemsQueue())
		{
			if(item.getObjectId() == obj_id)
				return item;
		}

		return null;
	}

	public Item[] getItems()
	{
		return _items.toArray(new Item[_items.size()]);
	}

	public Queue<Item> getItemsQueue()
	{
		return _items;
	}

	public int size()
	{
		return getItemsQueue().size();
	}

	// ==============================================================================================
	// Owner
	// ==============================================================================================
	@SuppressWarnings("unchecked")
	public OWNER getOwner()
	{
		return (OWNER) ObjectsStorage.getInstance().get(_storedId);
	}

	public void setOwner(OWNER owner)
	{
		_storedId = owner == null ? 0 : owner.getStoredId();
	}

	public int getOwnerId()
	{
		OWNER owner = getOwner();
		return owner == null ? 0 : owner.getObjectId();
	}

	// ==============================================================================================
	// Abstracts
	// ==============================================================================================
	public abstract ItemLocation getBaseLocation();

	public abstract ItemLocation getEquipLocation();
}